package com.zbkj.crmeb.store.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.constants.Constants;
import com.crmeb.core.config.RestTemplateConfig;
import com.pdd.pop.ext.apache.http.HttpResponse;
import com.pdd.pop.ext.apache.http.client.HttpClient;
import com.pdd.pop.ext.apache.http.client.methods.HttpPost;
import com.pdd.pop.ext.apache.http.entity.ContentType;
import com.pdd.pop.ext.apache.http.entity.StringEntity;
import com.pdd.pop.ext.apache.http.impl.client.HttpClientBuilder;
import com.pdd.pop.ext.apache.http.util.EntityUtils;
import com.zbkj.crmeb.express.model.Express;
import com.zbkj.crmeb.express.service.ExpressService;
import com.zbkj.crmeb.store.model.StoreOrder;
import com.zbkj.crmeb.store.model.StoreOrderInfo;
import com.zbkj.crmeb.store.service.TencentLogisticsService;
import com.zbkj.crmeb.system.model.SystemConfig;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.user.model.UserToken;
import com.zbkj.crmeb.user.service.UserTokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import springfox.documentation.annotations.Cacheable;

import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class TencentLogisticsServiceImpl implements TencentLogisticsService {


    private static final String URL = "https://api.weixin.qq.com/cgi-bin/express/business/order/add";
    @Autowired
    private RestTemplateConfig restTemplateConfig;
    @Autowired
    private ExpressService expressService;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private SystemConfigService systemConfigService;

    /**
     * 小程序物流发货
     * @param storeOrderInfo
     * @param order
     * @param express
     */
    @Override
    public void shipments(StoreOrderInfo storeOrderInfo, StoreOrder order, Express express) {
        // 创建请求数据
        JSONObject requestData = new JSONObject();
        try {
            // 构建order_key
            JSONObject orderKey = new JSONObject();
            orderKey.put("order_number_type", 1);
            orderKey.put("transaction_id", order.getOrderId());

            // 构建shipping_list中的一个物品信息
            JSONObject shippingItem = new JSONObject();
            shippingItem.put("tracking_no", order.getOrderId());
            shippingItem.put("express_company", express.getJkyExpressCode()); //物流公司
            shippingItem.put("item_desc", storeOrderInfo.getStoreName());
            if(express.getId() == 188){ //顺丰速运, 需要联系方式
                JSONObject contact = new JSONObject();
                contact.put("receiver_contact", maskPhoneNumber(order.getUserPhone()));
                shippingItem.put("contact", contact);
            }

            // 添加到发货物流单列表
            JSONArray shippingList = new JSONArray();
            shippingList.add(shippingItem);

            // 添加其余的字段
            requestData.put("order_key", orderKey);
            requestData.put("delivery_mode", 1);
            requestData.put("logistics_type", 1);
            requestData.put("shipping_list", shippingList);
            requestData.put("upload_time", ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

            JSONObject payer = new JSONObject();
            UserToken user = userTokenService.lambdaQuery()
                    .eq(UserToken::getUid, order.getUid())
                    .eq(UserToken::getType, 2).one();
            payer.put("openid", user.getToken());
            requestData.put("payer", payer);

            // 获取小程序access_token
            String accessToken = getAccessToken(order.getMerId());

            // 调用微信发货通知接口
            HttpClient client = HttpClientBuilder.create().build();
            HttpPost post = new HttpPost(URL + "?access_token=" + accessToken);

            // 设置请求体为JSON
            StringEntity entity = new StringEntity(requestData.toString(), ContentType.APPLICATION_JSON);
            post.setEntity(entity);

            // 发送请求并获取响应
            HttpResponse response = client.execute(post);

            // 处理响应
            if (response.getStatusLine().getStatusCode() == 200) {
                // 读取响应内容
                String responseContent = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                System.out.println("Response: " + responseContent);
            } else {
                System.out.println("Failed to send request with error code: " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取access_token
     * @param merId
     * @return
     */
    private String getAccessToken(Integer merId) {
        // 获取已存在令牌
        SystemConfig config = systemConfigService.lambdaQuery()
                .eq(SystemConfig::getName, Constants.CONFIG_KEY_PAY_ROUTINE_ACCESS_TOKEN + "_" + merId).one();


        Long diff = config != null ? (new Date().getTime() - config.getUpdateTime().getTime()) : -1;
        // 判断令牌是否还有效
        if (diff < 7200000 && diff != -1) {
            return config.getValue();
        }

        // 获取小程序的 appid 和 appsecret
        String appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID + "_" + merId);
        appId = null == appId ? systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID) : appId;
        String secret = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_SECRET + "_" + merId);
        secret = null == secret ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID) : secret;

        // 调用接口获取访问令牌
        RestTemplate restTemplate = restTemplateConfig.restTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + secret, String.class);
        JSONObject jsonObject = JSONObject.parseObject(response.getBody());

        if (jsonObject.containsKey("access_token")) {
            String accessToken = jsonObject.getString("access_token");


            // 更新存在的令牌access_token
            if(!BeanUtil.isEmpty(config)) {
                config.setValue(accessToken)
                        .setUpdateTime(new Date());
            }else { //创建新的access_token
                config = new SystemConfig()
                        .setName(Constants.CONFIG_KEY_PAY_ROUTINE_ACCESS_TOKEN + "_" + merId)
                        .setTitle(Constants.CONFIG_KEY_PAY_ROUTINE_ACCESS_TOKEN)
                        .setValue(accessToken)
                        .setStatus(false)
                        .setCreateTime(new Date())
                        .setUpdateTime(new Date());
            }
            systemConfigService.saveOrUpdate(config);
            return config.getValue();
        } else {
            log.error("-----------获取微信token失败,msg:{}-----------", jsonObject.getString("errmsg"));
            return null;
        }
    }

    /**
     * 手机号码掩码处理
     * @param phoneNumber
     * @return
     */
    private String maskPhoneNumber(String phoneNumber) {
        // 正则表达式用于找到倒数第四位数字之前的所有内容
        String regex = "(.*)(\\d{4})$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(phoneNumber.replaceAll("[^0-9]", "")); // 去除所有非数字字符，简化处理

        if (matcher.find()) {
            String start = matcher.group(1); // 匹配到的开始部分，需要被掩码
            String end = matcher.group(2); // 最后四位数字，保留不掩码

            // 将开始部分中的数字替换为星号
            String maskedStart = start.replaceAll("\\d", "*");

            // 恢复原格式中非数字字符的位置
            int index = 0;
            StringBuilder formattedMaskedStart = new StringBuilder();
            for (char c : phoneNumber.toCharArray()) {
                if (Character.isDigit(c)) {
                    if (index < maskedStart.length()) {
                        formattedMaskedStart.append(maskedStart.charAt(index++));
                    } else {
                        formattedMaskedStart.append(c);  // 保留最后四位数字
                    }
                } else {
                    formattedMaskedStart.append(c);  // 保留非数字字符
                }
            }

            return formattedMaskedStart.toString();
        } else {
            // 如果没有匹配到四位数字，直接返回原号码
            return phoneNumber;
        }
    }
}
